package project.check.attribute;

import java.util.regex.Pattern;

import online.model.ModelUtil;
import online.model.check.ItemCheckException;
import online.model.check.KeepCheckException;
import project.check.BaseCheck;
import project.master.MsgUtil;
import core.util.ArrayUtil;
import core.util.MojiUtil;

/**
 * 入力文字列が変換可能かチェックする。
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class MojiReferenceCheck extends BaseCheck {

	/** 数値文字参照10進 */
	private static final Pattern PATTERN_DEC = Pattern.compile("&#[0-9]{2,5};");
	/** 数値文字参照16進 */
	private static final Pattern PATTERN_HEX = Pattern.compile("&#x[0-9A-Fa-f]{4};");

	/** カナチェック */
	private final boolean k;
	/** 外字チェック */
	private final boolean e;
	/** メッセージID */
	private final String mid;
	/** メッセージパラメータ */
	private final String[] prm;

	/**
	 * コンストラクタ
	 */
	public MojiReferenceCheck() {
		this(true, true);
	}

	/**
	 * コンストラクタ
	 * @param kana 半角カナを含む場合 true
	 * @param ext ユーザ定義領域を含む場合 true
	 */
	public MojiReferenceCheck(final boolean kana, final boolean ext) {
		this.k = kana;
		this.e = ext;
		this.mid = null;
		this.prm = null;
	}

	/**
	 * コンストラクタ
	 *
	 * @param kana 半角カナを含む場合 true
	 * @param ext ユーザ定義領域を含む場合 true
	 * @param msgId メッセージID
	 * @param param メッセージパラメータ
	 */
	public MojiReferenceCheck(final boolean kana, final boolean ext,
			final String msgId, final String... param) {
		this.k = kana;
		this.e = ext;
		this.mid = msgId;
		this.prm = ArrayUtil.copyOf(param);
	}

	/**
	 * @see online.model.check.ItemCheck#check(java.lang.String...)
	 */
	@Override
	public void check(final String... items) throws ItemCheckException {
		boolean check = true;
		for (final String item : items) {
			String[] val = super.getArrayParameter(item);
			for (int j = 0; val != null && j < val.length; j++) {
				if (super.isDeleted(j)) {
					val[j] = ModelUtil.getValueAsString(super.getUniModel(), item, j);
					continue;
				}
				if (isMojiReference(val[j])) {
					if (!MsgUtil.hasItemMessage(super.getUniModel(), item)) {
						super.addTopMessage(this.mid, this.prm);
					}
					if (!MsgUtil.hasItemMessage(super.getUniModel(), item)) {
						MsgUtil.putItemMessage(super.getUniModel(), item, j, this.mid, this.prm);
					}
					check = false;
				}
			}
		}

		if (!check) {
			throw new KeepCheckException();
		}
	}

	/**
	 * 数値文字参照か判断します。
	 * @param val 対象文字列
	 * @return 文字参照が存在する場合 true を返す。
	 */
	private boolean isMojiReference(final String val) {
		return MojiUtil.isShiftJIS(val, this.k, this.e)
				&& (PATTERN_DEC.matcher(val).matches() || PATTERN_HEX.matcher(val).matches());
	}
}
